// $Id: Validatable.cs 18 2007-04-26 13:19:49Z mcartoixa $

using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Reflection;
using Salamanca.DataRules;

namespace Salamanca.NUnit.DataRules
{
    internal abstract class Validatable:
        IValidatable
    {
        #region IValidatable
        public bool Validate()
        {
            return Validate(null);
        }

        public bool Validate(string propertyName)
        {
            OnValidating(new ValidationEventArgs(propertyName));

            return Salamanca.DataRules.Rules.Validate(this, propertyName, Rules);
        }

        private ReadOnlyCollection<IRule> GetBrokenRules()
        {
            OnValidating(new ValidationEventArgs());

            return GetBrokenRules(null);
        }

        private ReadOnlyCollection<IRule> GetBrokenRules(string propertyName)
        {
            OnValidating(new ValidationEventArgs(propertyName));

            return Salamanca.DataRules.Rules.GetBrokenRules(this, propertyName, Rules);
        }

        bool IValidatable.Validate(string propertyName)
        {
            return Validate(propertyName);
        }

        IList<IRule> IValidatable.GetBrokenRules()
        {
            return GetBrokenRules();
        }

        protected virtual void OnValidating(ValidationEventArgs e)
        {
            if (Validating!=null)
                Validating(this, e);
        }


        IList<IRule> IValidatable.GetBrokenRules(string propertyName)
        {
            return GetBrokenRules(propertyName);
        }

        private List<IRule> Rules
        {
            get
            {
                // Get the list of intrinsic rules
                if (_Rules==null)
                {
                    List<IRule> tmp=new List<IRule>(CreateRules());

                    // Validate ... the rules !
                    foreach (IRule r in tmp)
                    {
                        // The property name must be valid for this type
                        bool check=
                            (r.PropertyName.Length==0)||
                            (GetType().GetProperty(r.PropertyName, BindingFlags.Instance|BindingFlags.Public|BindingFlags.FlattenHierarchy)!=null);
                        Debug.Assert(check);
                        if (!check)
                            throw new InvalidOperationException();
                    }

                    _Rules=tmp;
                }

                return _Rules;
            }
        }

        IList<IRule> IValidatable.Rules
        {
            get
            {
                return Rules;
            }
        }
        #endregion

        protected virtual IList<IRule> CreateRules()
        {
            return Salamanca.DataRules.Rules.CreateRules(GetType());
        }

        public event EventHandler<ValidationEventArgs> Validating;

        private List<IRule> _Rules;

    }
}
